package top.wshape1.shiziapi.mock.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import top.wshape1.shiziapi.common.constant.BizCodeEnum;
import top.wshape1.shiziapi.common.exception.CustomException;
import top.wshape1.shiziapi.common.utils.R;
import top.wshape1.shiziapi.mock.domain.Mock;
import top.wshape1.shiziapi.mock.domain.vo.HeaderVo;
import top.wshape1.shiziapi.mock.domain.vo.MockVo;
import top.wshape1.shiziapi.mock.mapper.MockMapper;
import top.wshape1.shiziapi.mock.service.JsEngineService;
import top.wshape1.shiziapi.mock.service.MockService;

import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author Wshape1
 * @description 针对表【t_mock】的数据库操作Service实现
 * @since 2023-10-09 21:35:11
 */
@Service
public class MockServiceImpl extends ServiceImpl<MockMapper, Mock>
        implements MockService {

    private final String PATH_REGEX = "^/[a-zA-Z0-9-_]+$";

    @Resource
    private JsEngineService jsEngineService;

    @Override
    public long create(Mock mock, Long userId) {

        if (getByUserIdAndPath(userId, mock.getPath()) != null)
            throw new CustomException(R.instance(BizCodeEnum.MOCK_PATH_EXIST_ERROR));

        if (!mock.getPath().matches(PATH_REGEX) ||
                !mock.getTemplate().startsWith("{") ||
                !mock.getTemplate().endsWith("}"))
            throw new CustomException(R.instance(BizCodeEnum.INVALID_DATA_ERROR));

        mock.setUserId(userId);
        mock.setCreateTime(new Date());

        save(mock);

        return mock.getId();
    }

    @Override
    public Mock getByIdAndUserId(String mockId, Long userId) {

        Mock mock = this.getOne(new LambdaQueryWrapper<Mock>()
                .eq(Mock::getId, mockId)
                .eq(Mock::getUserId, userId));

        return mock;
    }

    @Override
    public void update(Mock mock, Long userId) {

        // 数据校验
        if (!Objects.equals(mock.getUserId(), userId) ||
                !mock.getPath().matches(PATH_REGEX) ||
                (!mock.getTemplate().startsWith("{") || !mock.getTemplate().endsWith("}")))
            throw new CustomException(R.instance(BizCodeEnum.INVALID_DATA_ERROR));

        if (mock.getId() == null)
            throw new CustomException(R.instance(BizCodeEnum.MOCK_NOT_EXIST_ERROR));

        Mock one = getById(mock.getId());

        // 查询路径是否存在，允许路径不修改
        Mock other = getByUserIdAndPath(userId, mock.getPath());
        if (other != null && !Objects.equals(one.getId(), other.getId()))
            throw new CustomException(R.instance(BizCodeEnum.MOCK_PATH_EXIST_ERROR));

        updateById(mock);
    }

    private Mock getByUserIdAndPath(Long userId, String path) {
        return getOne(new LambdaQueryWrapper<Mock>()
                .eq(Mock::getUserId, userId)
                .eq(Mock::getPath, path));
    }

    @Override
    public void remove(Long mockId, Long id) {
        if (getOne(new LambdaQueryWrapper<Mock>()
                .eq(Mock::getId, mockId)
                .eq(Mock::getUserId, id)) == null) {
            throw new CustomException(R.instance(BizCodeEnum.MOCK_NOT_EXIST_ERROR));
        }

        removeById(mockId);

    }

    @Override
    public List<MockVo> list(Long userId, String keyword) {

        List<Mock> list = this.list(new LambdaQueryWrapper<Mock>()
                .eq(Mock::getUserId, userId)
                .orderByDesc(Mock::getCreateTime)
                .select(Mock::getId, Mock::getName, Mock::getMethod, Mock::getPath)
                .like(keyword != null, Mock::getName, keyword)
        );

        return list.stream()
                .map(mock -> new MockVo(mock.getId(), mock.getName(), mock.getMethod(), mock.getPath()))
                .toList();
    }

    @Override
    public Object mockRequest(Long userId, String path, HttpServletRequest request, HttpServletResponse response) throws ScriptException {

        Mock mock = getByUserIdAndPath(userId, path);
        if (mock == null || !request.getMethod().equalsIgnoreCase(mock.getMethod())) {
            throw new CustomException(R.error("MOCK配置查找不到，请注意method+url是否正确"));
        }

        // 设置响应状态码
        response.setStatus(mock.getResponseCode());

        // 设置响应头
        for (HeaderVo headerVo : JSON.parseObject(mock.getResponseHeaders(), new TypeReference<List<HeaderVo>>() {
        })) {
            response.setHeader(headerVo.getHeader(), headerVo.getValue());
        }

        return jsEngineService.mock(mock.getTemplate());
    }
}




